package org.loong.crypto.core.utils;

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import org.loong.crypto.common.exception.CryptoException;
import org.loong.crypto.common.exception.InvalidKeyException;
import org.loong.crypto.core.GlobalBouncyCastleProvider;

/**
 * DSA Key conversion utility.
 */
public class DSAKeyUtils {

    /**
     * Returns the private DSA key of the specified DSA key.
     *
     * @param key the DSA key bytes. Must not be {@code null}.
     * @return the DSA private key.
     * @throws CryptoException the DSA key transformation failed.
     */
    public static DSAPrivateKey toDSAPrivateKey(final byte[] key) throws CryptoException {
        final Provider provider = GlobalBouncyCastleProvider.INSTANCE.getProvider();
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("DSA", provider);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key);
            DSAPrivateKey privateKey = (DSAPrivateKey) keyFactory.generatePrivate(keySpec);
            if (privateKey == null) {
                throw new InvalidKeyException("The DSA private key transformation failed");
            }
            return privateKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new InvalidKeyException("The DSA private key transformation failed"); 
        } 
    }
    
    /**
     * Returns the public DSA key of the specified DSA key.
     *
     * @param key the DSA key bytes. Must not be {@code null}.
     * @return the DSA public key.
     * @throws CryptoException the DSA key transformation failed.
     */
    public static DSAPublicKey toDSAPublicKey(final byte[] key) throws CryptoException {
        final Provider provider = GlobalBouncyCastleProvider.INSTANCE.getProvider();
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("DSA", provider);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
            DSAPublicKey publicKey = (DSAPublicKey) keyFactory.generatePublic(keySpec);
            if (publicKey == null) {
                throw new InvalidKeyException("The DSA public key transformation failed");
            }
            return publicKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new InvalidKeyException("The DSA public key transformation failed"); 
        } 
    }

    /**
     * Returns the length in bits of the specified DSA private key.
     *
     * @param privateKey The DSA private key. Must not be {@code null}.
     *
     * @return The key length in bits.
     */
    public static int keyBitLength(final PrivateKey privateKey) {
        if (!(privateKey instanceof DSAPrivateKey)) {
            return -1; 
        }

        DSAPrivateKey rsaPrivateKey = (DSAPrivateKey) privateKey;
        try {
            return rsaPrivateKey.getX().bitLength();
        } catch (Exception e) {
            return -1;
        }
    }
}
